<template>
  <div style="width: 100%">
      <a-radio-group class="mapType" v-model:value="mapType">
      <a-radio-button
        v-for="(item, index) in mapInfo.tileLayer"
        :key="index"
        :value="item"
        @click="changeMapType(item)"
      >
         {{ getLaterName(item)}}
        
      </a-radio-button>
    </a-radio-group>
    <div style="width: 100%; height: 100%" :id="mapInfo.mapId"></div>
    <div>
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default{
  props:['mapInfo'],
  data(){
    return {
      map:null,//地图实例
      mapType: 'TileLayer',//地图类型
      mapGeocoder:null,//搜索插件实例
      mapOverView:null,//鹰眼插件实例
      mapScale:null,//比例尺插件实例
      mapToolBar:null,//工具栏插件实例
      mapMarkers:[],//标记列表
      parent:null,
      parentFlowData:[]
    }
  },
  mounted(){
    this.mapInit()
  },
  methods: {
    // 点击切换地图类型  获取地图类型
    changeMapType(type) {
      let layer = []
      switch (type) {
        case 'TileLayer':
          layer = [new AMap.TileLayer()]
          break
        case 'Satellite':
          layer = [new AMap.TileLayer.Satellite()]
          break
        case 'Traffic':
          layer = [new AMap.TileLayer()]
          break
        case 'RoadNet':
          layer = [new AMap.TileLayer.RoadNet(), new AMap.TileLayer.Satellite()]
          break
        default:
          layer = []
      }
      if (this.map) {
        this.map.setLayers(layer)
        if (type === 'Traffic') {
          const trafficLayer = new AMap.TileLayer.Traffic({
            zIndex: 10,
          })
          trafficLayer.setMap(this.map)
        }
      }
    },
    //加载高德
    mapLoader() {
      return new Promise((resolve, reject) => {
        if (window.AMap) {
          resolve(window.AMap)
        } else {
          const url = `https://webapi.amap.com/maps?v=1.4.15&key=${this.mapInfo.mapKey}&callback=onLoad${this.mapInfo.mapId}&plugin=AMap.ToolBar,AMap.Scale,AMap.OverView,AMap.Geocoder`
          const script = document.createElement('script')
          script.charset = 'utf-8'
          script.src = url
          script.onerror = reject
          script.setAttribute('mapScript', this.mapInfo.mapId)
          document.head.appendChild(script)
        }
        window[`onLoad${this.mapInfo.mapId}`] = () => {
          resolve(window.AMap)
        }
      })
    },
    //控制插件显隐
    setMapControl(){
      const { ToolBar, OverView, Scale } = this.mapInfo
      OverView ? this.mapOverView.show() : this.mapOverView.hide()
      ToolBar ? this.mapToolBar.show() : this.mapToolBar.hide()
      Scale ? this.mapScale.show() : this.mapScale.hide()
    },
    //插件地图
    createMap(){
      const {
        zoom,
        resizeEnable,
        animateEnable,
        dragEnable,
        zoomEnable,
        doubleClickZoom,
        keyboardEnable,
        jogEnable,
        scrollWheel,
        ToolBar,
        OverView,
        Scale,
        mapLng,
        mapLat,
        centerAddress,
        mapId
      } = this.mapInfo
      this.map = new AMap.Map(mapId, {
        enableHighAccuracy: true,
        convert: true,
        center:[mapLng,mapLat],
        zoom,
        resizeEnable,
        animateEnable,
        dragEnable,
        zoomEnable,
        doubleClickZoom,
        keyboardEnable,
        jogEnable,
        scrollWheel,
      })
      this.mapGeocoder = new AMap.Geocoder({
        radius: 1000,
        extensions: 'all',
      })
      this.mapOverView = new AMap.OverView()
      this.mapScale = new AMap.Scale()
      this.mapToolBar = new AMap.ToolBar()
      this.map.addControl(this.mapScale)
      this.map.addControl(this.mapToolBar)
      this.map.addControl(this.mapOverView)
      this.setMapControl()
      this.findParent()
      if(this.mapInfo.childrenSourceList?.length>0) this.addMarker()
      if(centerAddress) this.getCenterAddress(centerAddress,'create')
    },
    //地图初始化
    mapInit(){
      const that = this
      this.$nextTick(()=>{
        this.mapLoader().then( async ()=>{
          await that.createMap()
          that.map&&this.mapInfo?.isMapClick&&that.map.on('click',that.mapClick)
        })
      })
    },
    mapClick(e){
      this.getCenterAddress(e.lnglat,'mapClick')
    },
    /* 地图编码 逆编码
       * type   create-初始化  addressChange-位置改变时 itemChildren-子组件位置修改时 mapClick-地图点击_逆编码
       */
    getCenterAddress(centerAddress,type,staticProp,content){
      if(type!=='mapClick') {
        this.mapGeocoder.getLocation(centerAddress,  (status, result)=> {
          if (status === 'complete' && result.geocodes.length) {
            const lnglat = result.geocodes[0].location
            if(type==='itemChildren'){
              const marker = new AMap.Marker({
                ...staticProp,
                content,
                offset: new AMap.Pixel(-15, -25),
              })
              marker.setPosition(lnglat)
              this.map.add(marker)
              this.map.setFitView()
              return 
            }else{
              this.map.remove(this.mapMarkers)
              const marker = new AMap.Marker({
                  position: lnglat,
                  anchor:'bottom-center',
                  offset: new AMap.Pixel(0, 0)
              })
              marker.setLabel({
                  direction:'right',
                  offset: new AMap.Pixel(10, 0),  //设置文本标注偏移量
                  content:centerAddress, //设置文本标注内容
              });
              this.mapMarkers.push(marker);
              this.map.add(marker)
              //地图改变修改 组件中心和位置
                this.mapInfo.centerAddress = centerAddress
                this.mapInfo.mapLng = lnglat['lng']
                this.mapInfo.mapLat = lnglat['lat']
            }
            this.map.setCenter(lnglat)
          } else {
            this.$message.error(`查询(${centerAddress})位置失败`)
          }
        })
      }else{
      //centerAddress此时时经纬度坐标  逆编码
        this.mapGeocoder.getAddress(centerAddress, (status, result)=> {
          if (status === 'complete'&&result.regeocode) {
            this.map.remove(this.mapMarkers)
            this.mapInfo.centerAddress = result.regeocode.formattedAddress;
          }else{
            this.$message.error('根据经纬度查询地址失败')
          }
        });
      }
    },
    // 获取地图类型
    getLaterName(type) {
      let name = ''
      switch (type) {
        case 'TileLayer':
          name = '标准'
          break
        case 'Satellite':
          name = '卫星图'
          break
        case 'Traffic':
          name = '实时路况'
          break
        case 'RoadNet':
          name = '卫星路网'
          break
        default:
          name = ''
      }
      return name
    },
     findParent(){
      this.parent = this
      const list = this.mapInfo.childrenSourceList || []
        while (this.parent) {
        //找到有流程返回数据的那层
        if (this.parent.$refs[list[0].identifier] || this.parent.$data.controlProperties) {
          list.forEach((item) => {
            const newInfo = this.parent.$data.controlProperties[item.identifier] //流程返回数据
            this.parentFlowData.push(newInfo)
          })
          return
        }
          this.parent = this.parent.$parent
        }
    },
    addMarker() {
      // let parent = this
      const list = this.mapInfo.childrenSourceList || []
      this.map.clearMap() // 先清除覆盖物
       list.forEach((item) => {
            const identifier = item.identifier
            const content = this.parent.$refs[identifier]  //点标记和信息窗口 所需要的dom元素
            const newInfo = this.parent.controlProperties[item.identifier] //流程返回数据
            if (item.dataType !== 'list') {
              let marker = this.getMarkerType(item.type, newInfo, content) //根据类型创建标记 和 覆盖物
              console.log(item.type,newInfo,marker)
              if (marker) marker.setMap(this.map)
            } else {
              const list = newInfo.markerList || []
              list.forEach(mapMarkerItem => {
                const itemNewInfo = {}
                Object.entries(item.dataSourceKey).forEach(itemKey => {
                  itemNewInfo[itemKey[0]] = mapMarkerItem[itemKey[1]]
                })
                // 赋值子组件的内容
                if (itemNewInfo?.mapMarkerContent) content.childNodes[1].innerHTML = itemNewInfo.mapMarkerContent
                const domContent = content?.cloneNode(true)
                const staticProp = this.setChildItemInfo(item, itemNewInfo)
                let marker = this.getMarkerType(item.type, staticProp, domContent) //根据类型创建标记 和 覆盖物
                if (marker) marker.setMap(this.map)
              })
            }
          })
      // 若是有标记或覆盖物 设置地图显示范围
      this.map.setFitView()
      this.show = true
    },
    
    setChildItemInfo(item,newInfo){
        let staticProp = item.staticProp
        const {
          centerAddress,
          mapLng,
          mapLat,
          mapMarkerTitle,
          circleLng,
          circleLat,
          markerStrokeColor,
          markerFillColor,
          circleRadius,
          polygonMarkerArray,
          ellipseRadiusLeft,
          ellipseRadiusRight,
          southWestLeft,
          southWestRight,
          northEastLeft,
          northEastRight,
          }=newInfo
        switch (item.type) {
          case 'MapMarker':
            if(this.setItemTemplate(centerAddress,'String')){
                staticProp.centerAddress =centerAddress
            }
            if(this.setItemTemplate(mapLng,'Number')){
                staticProp.position[0] =mapLng
            }
            if(this.setItemTemplate(mapLat,'Number')){
                staticProp.position[1] =mapLat
            }
            if(this.setItemTemplate(mapMarkerTitle,'String')){
                staticProp.title =mapMarkerTitle
            }
            break
          case 'MapCircleMarker':
            if(this.setItemTemplate(circleLng,'Number')){
              staticProp.center[0] =circleLng
            }
            if(this.setItemTemplate(circleLat,'Number')){
              staticProp.center[1] =circleLat
            }
            if(this.setItemTemplate(markerStrokeColor,'String')){
              staticProp.strokeColor =markerStrokeColor
            }
            if(this.setItemTemplate(markerFillColor,'String')){
              staticProp.fillColor =markerFillColor
            }
            if(this.setItemTemplate(circleRadius,'Number')){
              staticProp.radius =circleRadius
            }
            break
          case 'MapPolygonMarker':
            if(this.setItemTemplate(markerStrokeColor,'String')){
              staticProp.strokeColor =markerStrokeColor
            }
            if(this.setItemTemplate(markerFillColor,'String')){
              staticProp.fillColor =markerFillColor
            }
            if(this.setItemTemplate(polygonMarkerArray,'Array')){
              staticProp.path =polygonMarkerArray
            }
            break   
          case 'MapPolylineMarker':
            if(this.setItemTemplate(markerStrokeColor,'String')){
              staticProp.strokeColor =markerStrokeColor
            }
            if(this.setItemTemplate(polygonMarkerArray,'Array')){
              staticProp.path =polygonMarkerArray
            }
            break
          case 'MapEllipseMarker':
            if(this.setItemTemplate(circleLng,'Number')){
              staticProp.center[0] =circleLng
            }
            if(this.setItemTemplate(circleLat,'Number')){
              staticProp.center[1] =circleLat
            }
            if(this.setItemTemplate(ellipseRadiusLeft,'Number')){
              staticProp.radius[0] =ellipseRadiusLeft
            }
            if(this.setItemTemplate(ellipseRadiusRight,'Number')){
              staticProp.radius[1] =ellipseRadiusRight
            }
            if(this.setItemTemplate(markerStrokeColor,'String')){
              staticProp.strokeColor =markerStrokeColor
            }
            if(this.setItemTemplate(markerFillColor,'String')){
              staticProp.fillColor =markerFillColor
            }
            break
          case 'MapRectangleMarker':
            if(this.setItemTemplate(southWestLeft,'Number')){
              staticProp.southWest[0] =southWestLeft
            }
            if(this.setItemTemplate(southWestRight,'Number')){
              staticProp.southWest[1] =southWestRight
            }
            if(this.setItemTemplate(northEastLeft,'Number')){
              staticProp.northEast[0] =northEastLeft
            }
            if(this.setItemTemplate(northEastRight,'Number')){
              staticProp.northEast[1] =northEastRight
            }
            if(this.setItemTemplate(markerStrokeColor,'String')){
              staticProp.strokeColor =markerStrokeColor
            }
            if(this.setItemTemplate(markerFillColor,'String')){
              staticProp.fillColor =markerFillColor
            }
            break
          case 'MapInfoWindowMarker':
            if(this.setItemTemplate(circleLng,'Number')){
              staticProp.position[0] =circleLng
            }
            if(this.setItemTemplate(circleLat,'Number')){
              staticProp.position[1] =circleLat
            }
            break
          default:
        }
        return staticProp
      },
      setItemTemplate(column,type){
        let isTrue=column&&Object.prototype.toString.call(column)===`[object ${type}]`
        if(type==='Array'){
          isTrue = isTrue && column?.length>0
        }
        return isTrue
      },
      getMarkerType(type, staticProp, content,newInfo) {
      let marker = null
        switch (type) {
          case 'MapMarker':
              if(staticProp?.centerAddress){
                this.getCenterAddress(staticProp.centerAddress,'itemChildren',staticProp,content)
              }else{
                marker = new AMap.Marker({
                  ...staticProp,
                  position:[staticProp.mapLng,staticProp.mapLat],
                  content,
                  offset: new AMap.Pixel(-15, -25),
                })
              }
            break
          case 'MapCircleMarker':
              marker = new AMap.Circle({ 
                ...staticProp,
                center:[staticProp.circleLng,staticProp.circleLat],
                })
            break
          case 'MapPolygonMarker':
              marker = new AMap.Polygon({ ...staticProp })
            break
          case 'MapPolylineMarker':
              marker = new AMap.Polyline({ ...staticProp })
            break
          case 'MapEllipseMarker':
              marker = new AMap.Ellipse({ 
                ...staticProp,
                center:[staticProp.centerLeft,staticProp.centerRight],
                radius:[staticProp.radiusLeft,staticProp.radiusRight]
              })
            break
          case 'MapRectangleMarker':
              marker = new AMap.Rectangle({
                ...staticProp,
                bounds: new AMap.Bounds(
                  [staticProp.southWestLeft,staticProp.southWestRight],
                  [staticProp.northEastLeft,staticProp.northEastRight]
                ),
              })
            break
          case 'MapInfoWindowMarker':
              marker = new AMap.InfoWindow({
                ...staticProp,
                content,
                position:[staticProp.positionLeft,staticProp.positionRight],
                size: new AMap.Size(300, 100),
              })
            break
          default:
        }
        return marker
    },
  },
  watch:{
    //中心位置
    'mapInfo.centerAddress':{
      handler(address){
        this.map&&address&&this.getCenterAddress(address,'addressChange')
      }
    },
    //经度
    "mapInfo.mapLng":{
      handler(){
       this.map&&this.map.setCenter([this.mapInfo.mapLng,this.mapInfo.mapLat])
      }
    },
    //纬度
    "mapInfo.mapLat":{
      handler(){
        this.map&&this.map.setCenter([this.mapInfo.mapLng,this.mapInfo.mapLat])
      }
    },
    //缩放
    "mapInfo.zoom":{
      handler(){
        this.map&&this.map.setZoom(v)
      }
    },
    //插件
    "mapInfo.Scale":{
      handler(){
        this.map && this.setMapControl()
      }
    },
    "mapInfo.OverView":{
      handler(){
       this.map && this.setMapControl()
      }
    },
    "mapInfo.ToolBar":{
      handler(){
        this.map && this.setMapControl()
      }
    },
    //其余配置
    "mapInfo.dragEnable":{
      handler(){
        this.map && this.map.setStatus({dragEnable:this.mapInfo.dragEnable})
      }
    },
    "mapInfo.animateEnable":{
      handler(){
        this.map && this.map.setStatus({animateEnable:this.mapInfo.animateEnable})
      }
    },
    "mapInfo.resizeEnable":{
      handler(){
        this.map && this.map.setStatus({resizeEnable:this.mapInfo.resizeEnable})
      }
    },
    "mapInfo.zoomEnable":{
      handler(){
        this.map && this.map.setStatus({zoomEnable:this.mapInfo.zoomEnable})
      }
    },
    "mapInfo.doubleClickZoom":{
      handler(){
        this.map && this.map.setStatus({doubleClickZoom:this.mapInfo.doubleClickZoom})
      }
    },
    "mapInfo.keyboardEnable":{
      handler(){
        this.map && this.map.setStatus({keyboardEnable:this.mapInfo.keyboardEnable})
      }
    },
    "mapInfo.jogEnable":{
      handler(){
        this.map && this.map.setStatus({jogEnable:this.mapInfo.jogEnable})
      }
    },
    "mapInfo.scrollWheel":{
      handler(){
        this.map && this.map.setStatus({scrollWheel:this.mapInfo.scrollWheel})
      }
    },
    "parentFlowData":{
      handler(){
        this.addMarker()
      },deep:true
    },
  }
}
</script>
<style lang="less" scoped>
/deep/ .mapType {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  .ant-radio-button-wrapper {
    span {
      color: rgba(0, 0, 0);
    }
  }
  .ant-radio-button-wrapper-checked {
    background-color: @primary-color;
    span {
      color: rgba(255, 255, 255);
    }
  }
}
</style>